package top.chaol.t55557reader;

import android.app.*;
import android.content.*;
import android.content.res.*;
import android.hardware.usb.*;
import android.os.Handler;
import android.util.*;

import com.felhr.usbserial.UsbSerialDevice;
import com.felhr.usbserial.UsbSerialInterface;

import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.*;
import org.xmlpull.v1.*;
import java.util.logging.*;


/**
 * Created by chaol on 2019/6/20.
 */
public class UsbSerial {
    private static final String TAG = UsbSerial.class.getSimpleName();
    private static final String ACTION_USB_PERMISSION = "U_ARE_S_B";
    private BroadcastReceiver mUsbPermissionActionReceiver;
    private Context mContext;
    private UsbDeviceConnection mDeviceConnection;
    private UsbManager mUsbManager;
    private UsbDevice mUsbDevice;
    private UsbSerialDevice mUsbSerialDevice;
	private T55557Card mCard;
	private android.os.Handler mainHandler;
	ExecutorService singleThreadExecutor;

    public UsbSerial(Context context) {
        Log.i(TAG, "The construction method of StUsb had been executed!");
        mContext = context;
		mainHandler = new Handler();
        mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
		mCard = new T55557Card();
		singleThreadExecutor = Executors.newSingleThreadExecutor();
    }


    /** * 此方法用来开启USB */
    public void openSerial(CallBack callBack) {
        // 判断是否有使用USB HOST的权限。
        singleThreadExecutor.execute(new Runnable() {
            @Override
            public void run() {
                enumerateDevice(callBack);
                if(mUsbDevice == null)
                    return;
                if (mUsbManager.hasPermission(mUsbDevice)) {
                    // 有权限则连接StUSB设备
                    if(connectSerial())
                        mainHandler.post(() -> callBack.run(ErrorCode.SUCCESS));
                    else
                        mainHandler.post(() -> callBack.run(ErrorCode.ERROR_CONNECT_FAILED));
                } else {
                    // 没有权限则获得权限
                    obtainPermission(callBack);
                }
            }
        });

    }

    /** * 此方法用来连接StUSB设备 */
    private boolean connectSerial() {
		mDeviceConnection = mUsbManager.openDevice(mUsbDevice);
        mUsbSerialDevice = UsbSerialDevice.createUsbSerialDevice(mUsbDevice, mDeviceConnection);
		if (mUsbSerialDevice == null)
			return false;
		else
        	return mUsbSerialDevice.syncOpen();
    }

    public void closeSerial() {
        if (mUsbDevice == null || mDeviceConnection == null)
            return;
        mUsbSerialDevice.syncClose();
        mDeviceConnection.close();
        mUsbDevice = null;
        mDeviceConnection = null;
    }


    /** * 查找device，找到指定的HidUsb设备 */
    private void enumerateDevice(CallBack callBack) {
        if (mUsbManager != null) {
            Log.d(TAG, "enumerateDevice2");
            HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();

            if (!deviceList.isEmpty()) {
                Iterator deviceIterator = deviceList.values().iterator();
                while (deviceIterator.hasNext()) {
                    UsbDevice device = (UsbDevice) deviceIterator.next();
                    Log.v(TAG, "device = " + device);
                    // 获得USB设备列表，判断是否是要求的USB设备
                    if (mUsbSerialDevice.isSupported(device)) {
                        // 是要求的USB 设备的情况下，将此设备赋值给成员变量 mUsbDevice
                        mUsbDevice = device;
                        Log.d(TAG, "enumerateDevice: Get Device OK.");
                        return;
                    }
                }
                mainHandler.post(() -> callBack.run(ErrorCode.ERROR_NO_VALID_DEVICE));
            } else {
                Log.e(TAG, "enumerateDevice: Device list is null !!!");
                mainHandler.post( () -> callBack.run(ErrorCode.ERROR_NULL_LIST));
            }
        } else {
            Log.e(TAG, "enumerateDevice: USB manager is null !!!");
            mainHandler.post(() -> callBack.run(ErrorCode.ERROR_NULL_MANAGER));
        }
    }

    /** * 获取权限 */
    private void obtainPermission(CallBack callBack) {
        if (mUsbDevice != null) {
            mUsbPermissionActionReceiver = new BroadcastReceiver() {
                public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (ACTION_USB_PERMISSION.equals(action)) {
                        context.unregisterReceiver(this);//解注册
                        synchronized (this) {
                            Log.d(TAG,"afterObtainPermission");
                            if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                                afterObtainPermission(callBack);
                            } else {
                                Log.e(TAG,"Permission denied for device" + mUsbDevice);
                                mainHandler.post(() -> callBack.run(ErrorCode.ERROR_PERMISSION_DENIED));
                            }
                        }
                    }
                }
            };
            PendingIntent mPermissionIntent = PendingIntent.getBroadcast(mContext,
                    0, new Intent(ACTION_USB_PERMISSION), 0);
            mContext.registerReceiver(mUsbPermissionActionReceiver, new IntentFilter(ACTION_USB_PERMISSION));
            mUsbManager.requestPermission(mUsbDevice, mPermissionIntent);
        } else {
            mainHandler.post(() -> callBack.run(ErrorCode.ERROR_NULL_DEVICE));
        }
    }

    private void afterObtainPermission(CallBack callBack) {
        if (connectSerial())
            mainHandler.post(() ->callBack.run(ErrorCode.SUCCESS));
        else
            mainHandler.post(() ->callBack.run(ErrorCode.ERROR_CONNECT_FAILED));
    }


    public void configSerial() {
        if (mUsbSerialDevice == null)
            return;
        mUsbSerialDevice.setBaudRate(9600);
        mUsbSerialDevice.setDataBits(UsbSerialInterface.DATA_BITS_8);
        mUsbSerialDevice.setParity(UsbSerialInterface.PARITY_NONE);
        mUsbSerialDevice.setStopBits(UsbSerialInterface.STOP_BITS_1);
        mUsbSerialDevice.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
    }

	// 第一块写：56 3A 78 AB 
	// 第二块写：34 5D 60 26
    public void makeCard(final CallBack callBack) {
		singleThreadExecutor.execute(new Runnable(){
				@Override
				public void run()
				{
					byte[] _pwd = new byte[4];
					byte[] _dat = {0x56, 0x3a, 0x78, (byte)0xab};
					byte[] _buffer = new byte[20];
					T55557Card.ResponseStruct _res;
					mUsbSerialDevice.syncWrite(mCard.writeDataCmd((byte)0x00, false, false, _pwd, _dat).toByteArray(), 2000);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(mUsbSerialDevice.syncRead(_buffer, 2000) > 0) {
                        _res = mCard.parseResponse(_buffer);
                        if (_res.getStatus() != 0x0) {
                            if (_res.getDataLength() > 1) {
                                byte code = _res.getData()[0];
                                mainHandler.post(() -> callBack.run(mCard.getResponseStatusMessage(code)));
                            } else {
                                mainHandler.post(() -> callBack.run(mCard.getResponseStatusMessage()));
                            }
                            return;
                        }
                    }
					_dat[0]=0x34; _dat[1]=0x5d; _dat[2]=0x60;_dat[3]=0x26;
					mUsbSerialDevice.syncWrite(mCard.writeDataCmd((byte)0x01, false, false, _pwd, _dat).toByteArray(), 2000);
					_dat[0]=0x0;_dat[1]=0x0;_dat[2]=0x0;_dat[3]=0x0;
					for (byte i=2; i<7; i++) {
						mUsbSerialDevice.syncWrite(mCard.writeDataCmd(i, false, false, _pwd, _dat).toByteArray(), 2000);
					}
					mainHandler.post(new Runnable(){
							@Override
							public void run()
							{
								// TODO: Implement this method
								callBack.run(ErrorCode.SUCCESS);
							}
					});
					
				}
		});
    }

    public void readCard(final CallBack callBack) {
        singleThreadExecutor.execute(new Runnable(){
            @Override
            public void run()
            {
                byte[] _pwd = new byte[4];
                byte[] _block3 = new byte[12];
                byte[] _buffer = new byte[200];
                T55557Card.ResponseStruct _res;
                for(byte t=0x1; t<=3; t++) {
                    mUsbSerialDevice.syncWrite(mCard.readDataCmd((byte)(t+1), false, _pwd).toByteArray(), 2000);
                    if (mUsbSerialDevice.syncRead(_buffer, 2000) > 0) {
                       _res = mCard.parseResponse(_buffer);
                        if (_res.getStatus() != 0x0) {
                            if (_res.getDataLength() > 1) {
                                byte code = _res.getData()[0];
                                mainHandler.post(() -> callBack.run(mCard.getResponseStatusMessage(code)));
                            } else {
                                mainHandler.post(() -> callBack.run(mCard.getResponseStatusMessage()));
                            }
                            return;
                        }
                        System.arraycopy(_res.getData(), 0, _block3, 4*(t-1), 4);
                        _block3[4*(t-1)] ^= 0x34;
                        _block3[4*t-3] ^= 0x56;
                        _block3[4*t-2] ^= 0x78;
                        _block3[4*t-1] ^= 0xab;
                    } else {
                        Log.d(TAG, "After read cmd" + mCard.readDataCmd().toHexString());
                        mainHandler.post(() -> callBack.run(ErrorCode.ERROR_READ_FAILED));
                        return;
                    }
                }
//                mUsbSerialDevice.syncWrite(mCard.writeDataCmd((byte)0x01, false, false, _pwd, _dat).toByteArray(), 2000);
                byte temp = 0;
                for (int i=0, len=_block3.length, halfLen=len/2; i<halfLen; i++) {
                    temp = _block3[i];
                    _block3[i] = _block3[len - i -1];
                    _block3[len - i - 1] = temp;
                }
                mainHandler.post(new Runnable(){
                    @Override
                    public void run()
                    {
                        Log.d(TAG, "callback run");
                        callBack.run(ErrorCode.SUCCESS, _block3);
                    }
                });

            }
        });
    }


    private boolean isMyUsb(UsbDevice device) {
        XmlResourceParser xrp = mContext.getResources().getXml(R.xml.device_filter);
        int _vid = device.getVendorId(), _pid = device.getProductId();
        try {
            while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
                if (xrp.getEventType() == XmlResourceParser.START_TAG) {
                    //获取标签名称
                    String name = xrp.getName();
                    if(name.equals("usb-device")){
                        if (_vid == Integer.parseInt(xrp.getAttributeValue(1)) &&
                              _pid == Integer.parseInt(xrp.getAttributeValue(0)))
                            return true;
                    }
                }
                //下一个标签
                xrp.next();
            }
            return false;
        } catch (XmlPullParserException e) {
            Log.e(TAG, "isMyUsb");
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            Log.e(TAG, "isMyUsb");
            e.printStackTrace();
            return false;
        }
    }

    public interface CallBack {
        void run(ErrorCode res);
        void run(ErrorCode status, byte[] res);
    }

    public enum ErrorCode {
        SUCCESS,
        ERROR,
        ERROR_NULL_LIST,
        ERROR_NULL_MANAGER,
        ERROR_NULL_DEVICE,
        ERROR_NO_VALID_DEVICE,
        ERROR_CONNECT_FAILED,
        ERROR_PERMISSION_DENIED,
        ERROR_READ_FAILED,
        ERROR_WRITE_FAILED,
        SUCCESS_CONFIG, // "参数设置成功");
        ERROR_CARD_NOT_EXIST,// "卡不存在");
        ERROR_CARD_TYPE, // "卡和读卡器不匹配(就是要读卡的类型CARDID和读卡器不符合)");
        ERROR_KNOW, // "未知的错误");
        ERROR_PARAM, // "输入参数错误,校验错误或者输入命令不存在");
        ERROR_CMD_CODE; // "输入的指令代码不存在"
    }



//    public boolean sendData(){
//        if (mDeviceConnection == null)
//            return false;
//        mDeviceConnection.bulkTransfer(mEpOut, mDataStruct.toByteArray(), mDataStruct.toByteArray().length, 0);
//        return true;
//        //Log.d(TAG, mDataStruct.toByteArray().toString());
//    }
//    public void release() {
//        stop();
//    }
//
//    /** * 此方法用来设置监听器 * * @param listener */
//    public void setListener(StUsbListener listener) {
//        mListener = listener;
//    }
//    private void start() {
//        Log.i(TAG, "start method running!");
//        // 1.创建了一个关联当前线程(主线程)的Handler
//        mHandler = new Handler();
//        // 2.创建了一个自带Handler的工作线程，并启动线程
//        mHandlerThread = new HandlerThread("Hid_Thread");
//        mHandlerThread.start();
//        // 3.获得了工作线程的Handler对象
//        mHidHandler = new Handler(mHandlerThread.getLooper()) {
//            @Override
//            public void handleMessage(Message msg) {
//                handleMessageMethodForWorker(msg);
//            }
//        };
//    }
//
//    protected void handleMessageMethodForWorker (Message msg) {
//        switch (msg.what) {
//            // 收到GET_DATA_MSG消息时执行
//            case GET_DATA_MSG:
//                try {
//                    // 调用getData方法
//                    final String gd = getData();
//                    // 判断获得的数据不为0，监听器不为空，主线程的Handler不为空时执行
//                    // 向主线程发送消息，调用监听器的onCodeReceive方法
//                    if (gd != "" && mListener != null && mHandler != null) {
//                        mHandler.post(new Runnable() {
//                            @Override
//                            public void run() {
//                                mListener.onCodeReceive(gd);
//                            }
//                        });
//                    }
//                } catch (NullPointerException e) {
//                    // 抓去空指针异常
//                    e.printStackTrace();
//                    // 休眠50毫秒
//                    try {
//                        Thread.sleep(50);
//                    } catch (InterruptedException e1) {
//                        e1.printStackTrace();
//                    }
//                }
//
//                // 4.移除主线程任务队列中的可执行任务
//                if(mHandler!=null) {
//                    mHandler.removeCallbacks(mRunnable);
//                    // 5.向主消息队列中放置任务
//                    mHandler.post(mRunnable);
//                }
//                break;
//            default:
//                break;
//        }
//    }
//
//    private Runnable mRunnable = new Runnable() {
//        @Override
//        public void run() {
//            // 当主线程Handler不为空时执行清空消息队列中的消息，并发送GET_DATA_MSG消息。
//            if (mHidHandler != null) {
//                mHidHandler.removeMessages(GET_DATA_MSG);
//                mHidHandler.sendEmptyMessage(GET_DATA_MSG);
//            }
////            runInMainThread();
//        }
//    };
//
////    protected void runInMainThread() {
////        // 当主线程Handler不为空时执行清空消息队列中的消息，并发送GET_DATA_MSG消息。
////        if (mHidHandler != null) {
////            mHidHandler.removeMessages(GET_DATA_MSG);
////            mHidHandler.sendEmptyMessage(GET_DATA_MSG);
////        }
////    }
//
//    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
//    private void stop() {
//        mHandler.removeCallbacks(mRunnable);
//        mHandler = null;
//        if (mHandlerThread != null) {
//            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
//                mHandlerThread.quit();
//            } else {
//                mHandlerThread.quitSafely();
//            }
//            mHandlerThread = null;
//            mHidHandler = null;
//        }
//    }
//
//    private String getData() {
//        //return 你从底层获得的数据
//        StringBuffer _buffer = new StringBuffer(2048);
//        byte[] _data = new byte[1024];
//        mDeviceConnection.bulkTransfer(mEpIn, _data, 1024, 0);
//        for (int i=0, len=_data.length; i<len; i++) {
//            _buffer.append((char)_data[i]);
//        }
//        return _buffer.toString();
//    }
    //
//    /** * 这是一个监听器接收数据的接口 */
//    public interface StUsbListener {
//        void onCodeReceive(String code);
//    }

}
